import abc
import openpyxl as xlp
import re
from threading import Thread


class DataProcessBase(object):
    @abc.abstractmethod
    def parse_data(self):
        pass

    # @abc.abstractmethod
    # def run(self) -> None:
    #     pass


class PeriodicDataCalc(DataProcessBase):
    __head_sg1 = "05 01 00 01"
    __length1 = 0
    __head_sg3 = "05 01 00 00 01 01 01 01 00"
    __length2 = 0
    __fun_code = "12 01"
    __trigger_event_version = 0
    __up_Period = "00 02"
    __length3 = 0

    def __init__(self, rd: list):
        super(PeriodicDataCalc, self).__init__()
        self.raw_data = rd
        self.ans_instruction = ""

    def check_data(self):
        pass

    def calc_can_info(self, can_id, msb, lsb):
        id = can_id & 0x3ff
        msb = msb & 0x1ff
        lsb = lsb & 0x1ff
        code = hex((id << 18) | (msb << 9) | (lsb))
        strip_prefix = code[2:]
        if len(strip_prefix) < 8:
            strip_prefix = '0' * (8 - len(strip_prefix)) + strip_prefix
        ans = []
        for i in range(0, len(strip_prefix), 2):
            ans.append(strip_prefix[i:i + 2])
        ret = " ".join(ans)
        return ret

    def parse_data(self):
        for ri in range(1, len(self.raw_data)):
            tmp = self.calc_can_info(self.raw_data[ri][3],
                                     self.raw_data[ri][4],
                                     self.raw_data[ri][5])
            self.ans_instruction.join(tmp)
        return self.ans_instruction


class CompleteDataCalc(DataProcessBase):
    def __init__(self, rd: list):
        super(CompleteDataCalc, self).__init__()
        self.raw_data = rd
        self.ans_instruction = ""

        # 自定义数据
        self.__some_ip_head = "05 01 00 03 00 00 00 04 01 01 01 00"
        self.__length1 = ""
        self.__payload = ""
        self.__col_mode = ""
        self.__can_id_num = 0

    def check_data(self):
        pass

    def parse_data(self):
        title_line = self.raw_data[1]
        id_idx = 0
        for idx, title in enumerate(title_line):
            if re.match("canid",title):
                id_idx = idx
        id_list = []
        for idx in range(len(self.raw_data)):
            pass
        return self.ans_instruction


class EventDataCalc(DataProcessBase):
    head_sg1 = "05 01 00 07 "
    head_data_length = 0
    head_sg3 = "00 00 00 04 01 01 01 00 "
    payload_length = 0
    fun_code = "12 06 "
    trigger_event_version = "00 0E "
    trigger_event_mod = '01 '
    trigger_event_id = ''
    trigger_event_num = 0
    ArrayLength = ""
    msg_num = 0
    msg_start_flag = "2A 2F "
    msg_end_flag = "2F 2A "

    def __init__(self, rd: list):
        super(EventDataCalc, self).__init__()
        # 存储excel中的原始数据
        self.raw_data = rd
        self.ans_instruction = ""
        # TODO:添加非变数据等
        self.trigger_event_num = len(self.raw_data) - 2
        self.msg_num = len(self.raw_data[1])

        self.ArrayLength = self.trigger_event_num * 16 + self.msg_num * 2 + 10
        self.payload_length = self.ArrayLength + 10
        self.head_data_length = self.payload_length + 12

    # 填充0
    def supplement_msg(self, message, length):
        i = 0
        message = str(message)
        msg_len = len(message)
        while i < length - msg_len:
            message = '0' + message
            i = i + 1
        return message

    def add_information(self, information, length):
        message = self.supplement_msg(information, length)
        length = len(message)
        counter = 0
        while counter < length + length / 2:
            if (counter % 3) == 0 or (counter % 3) == 1:
                self.ans_instruction = self.ans_instruction + message[(counter - int(counter / 3)):(
                            (counter - int(counter / 3)) + 1)]
            else:
                self.ans_instruction = self.ans_instruction + ' '
            counter = counter + 1

    def get_sig_msg(self, msb, lsb):
        return hex(int(bin(msb) + (self.supplement_msg(bin(lsb)[2:], 9)), 2))

    def set_head(self):
        self.ans_instruction += self.head_sg1
        self.add_information(hex(self.head_data_length)[2:], 8)
        self.ans_instruction += self.head_sg3
        self.add_information(hex(self.payload_length)[2:], 8)

    def set_trigger(self):
        self.ans_instruction += self.msg_start_flag
        counter_event = 2
        while counter_event < self.trigger_event_num + 2:
            # add trigger event mode
            self.ans_instruction += self.trigger_event_mod
            # add trigger event id
            self.add_information(str(self.raw_data[counter_event][2]), 4)
            # add signal message
            msb = self.raw_data[counter_event][3]
            lsb = self.raw_data[counter_event][4]
            sig_msg = self.get_sig_msg(msb, lsb)[2:]
            self.add_information(sig_msg, 6)
            # add event condition
            trigger_condition = self.raw_data[counter_event][5]
            self.add_information(trigger_condition, 2)
            # add event condition value
            condition_value = self.raw_data[counter_event][6]
            self.add_information(condition_value, 6)
            # add event time
            b_trigger_time = self.raw_data[counter_event][7] * 1000
            a_trigger_time = self.raw_data[counter_event][8] * 1000
            self.add_information(hex(b_trigger_time)[2:], 6)
            self.add_information(hex(a_trigger_time)[2:], 6)
            counter_event += 1
        self.ans_instruction += self.msg_end_flag

        self.ans_instruction += self.msg_start_flag
        # add collect ID num
        self.add_information(hex(self.msg_num)[2:], 4)
        # add collect ID
        counter_event = 0
        while counter_event < self.msg_num:
            collect_id = self.raw_data[1][counter_event]
            self.add_information(str(collect_id), 4)
            counter_event += 1
        self.ans_instruction += self.msg_end_flag

    def set_message(self):
        self.ans_instruction += self.fun_code
        self.ans_instruction += self.trigger_event_version
        self.add_information(hex(self.trigger_event_num)[2:], 4)
        self.add_information(hex(self.ArrayLength)[2:], 8)
        self.set_trigger()

    def parse_data(self):
        # 设置数据head
        self.set_head()
        self.set_message()
        return self.ans_instruction


class DataProcessThread(Thread):
    def __init__(self, col_mode, raw_data):
        Thread.__init__(self)
        self.__col_mode = col_mode
        self.__raw_data = raw_data
        self.__parsed_data = ""

    def run(self) -> None:
        if self.__col_mode == "周期收集":
            self.__parsed_data = PeriodicDataCalc(self.__raw_data).parse_data()
        elif self.__col_mode == "触发收集":
            self.__parsed_data = EventDataCalc(self.__raw_data).parse_data()
        else:
            self.__parsed_data = CompleteDataCalc(self.__raw_data).parse_data()

    def get_parsed_data(self):
        return self.__parsed_data


class DataProcessor(object):
    __file_path = ""
    __col_mode = ""

    def __init__(self, signalFilePath=""):
        super().__init__()
        self.__file_path = signalFilePath
        self.raw_data = []
        self.parsed_data = []

    def set_signal_file_path(self, file_path):
        self.__file_path = file_path

    def set_col_mode(self, col_mode):
        self.__col_mode = col_mode

    def get_raw_information(self):
        wb = xlp.load_workbook(self.__file_path)
        ws = wb[self.__col_mode]
        print(ws.max_row)
        for row in ws.rows:
            one_msg_info = []
            for cell in row:
                one_msg_info.append(cell.value)
            if one_msg_info:
                self.raw_data.append(one_msg_info)
        return self.raw_data

    def parse_raw_data(self):
        dpt = DataProcessThread(self.__col_mode, self.raw_data)
        dpt.start()
        dpt.join()
        self.parsed_data = dpt.get_parsed_data()
        return self.parsed_data

    def get_instruction(self):
        self.get_raw_information()
        return self.parse_raw_data()
